class AsyncSeriesWaterfallHook {
    events = [];
    promiseEvents = [];


    constructor(...args) {
        console.log('AsyncSeriesWaterfallHook');
        this.argsLength = args[0].length;
    }

    tapAsync(name, cb) {
        cb = typeof cb === 'function' ? cb : (...args) => args;
        this.events.push(cb);
    }

    tapPromise(name, cb) {
        cb = typeof cb === 'function' ? cb : (...args) => args;
        this.promiseEvents.push(cb);
    }

    callAsync(...args) {
        const callAsyncEvent = args.pop();
        const event = this.events.shift();
        const next = (...args1) => {
            const err = args1[0];
            const params = [args1[1], ...args.slice(1)].slice(0, this.argsLength);
            if (err === null || err === undefined || err === false) {
                if (this.events.length === 0) {
                    callAsyncEvent && callAsyncEvent();
                    return;
                }
                this.events.shift()(...params, next);
            } else {
                callAsyncEvent && callAsyncEvent(args1[1], undefined);
            }
        }
        event(...args, next);
    }

    promise(...args) {
        return this.promiseEvents.reduce((fn1, fn2) => {
            return (...args1) => {
                return fn1(...args1).then((...arg2) => {
                    return fn2(...arg2, ...args.slice(arg2.length))
                });
            }
        })(...args);
    }
}

module.exports = AsyncSeriesWaterfallHook;